package cn.z2huo.knowledge.concurrency.lock.reentrantlock.condition;

import cn.hutool.core.thread.ThreadUtil;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <p>
 *
 * @author z2huo
 */
class ReentrantCommunicationTest {

    static Lock lock = new ReentrantLock();

    static Condition condition = lock.newCondition();

    /**
     * 等待线程的异步目标任务
     */
    static class WaitTarget implements Runnable {
        @Override
        public void run() {
            // 获取到锁之前会一直阻塞
            lock.lock();
            try {
                System.out.println("等待方");
                // 调用 wait 方法，当前线程进入等待状态，当前线程会加入 Condition 对象等待队列中
                // 调用 wait 方法之后，会释放当前线程占用的对象锁
                condition.await();
                System.out.println("收到通知，等待方继续执行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

    /**
     * 通知线程的异步目标任务
     */
    static class NotifyTarget implements Runnable {

        @Override
        public void run() {
            // 获取到锁之前会一直阻塞
            lock.lock();
            try {
                System.out.println("通知方");
                // 在调用唤醒方法之后，会从 Condition 对象等待队列中唤醒一个线程
                condition.signal();
                System.out.println("发出通知，但是线程还未释放锁");
            } finally {
                // 释放锁之后，等待线程才能获取到锁
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        // 等待线程
        WaitTarget waitTarget = new WaitTarget();
        Thread waitThread = new Thread(waitTarget, "wait thread");
        waitThread.start();

        ThreadUtil.sleep(1, TimeUnit.SECONDS);

        // 通知线程
        NotifyTarget notifyTarget = new NotifyTarget();
        Thread notifyThread = new Thread(notifyTarget, "notify thread");
        notifyThread.start();
    }

}
